package com.itzmn.java.javase.io.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set;

/**
 * @Author: 张梦楠
 * @Date: 2018/12/26 15:41
 * 简书：https://www.jianshu.com/u/d611be10d1a6
 * 码云：https://gitee.com/zhangqiye
 * @Description: nio socket
 * 1.打开通道
 * 2.绑定端口
 * 3.设置管理者
 * 4.处理事件
 *
 */
public class NIOServer {

    private int port;
    private Selector selector;

    public NIOServer(){
        this(8080);
    }
    public NIOServer(int port) {
        this.port = port;
        try {
            // 1.打开通道
            ServerSocketChannel socketChannel = ServerSocketChannel.open();
            // 2. 绑定端口
            socketChannel.bind(new InetSocketAddress(port));
            // 3.设置为非阻塞模式
            socketChannel.configureBlocking(false);
            // 4.得到管理者
            selector = Selector.open();
            // 5.给通道注册一个连接事件
            socketChannel.register(selector,SelectionKey.OP_ACCEPT);

            System.out.println("服务端启动成功，port:"+this.port);
        } catch (IOException e) {
            System.out.println("服务端启动失败...");
            e.printStackTrace();
        }
    }

    /**
     * 监听这个管理者内部的等待者个数
     * @throws IOException
     */
    private void listen() throws IOException {
        while (true){
            int wait = selector.select();
            while (wait == 0){
                continue;
            }
            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            Iterator<SelectionKey> iterator = selectionKeys.iterator();
            while (iterator.hasNext()){
                SelectionKey next = iterator.next();
                process(next);
                iterator.remove();
            }
        }
    }

    /**
     * 处理这个key
     * @param key
     */
    private void process(SelectionKey key) throws IOException {

        // 连接事件
        if (key.isAcceptable()){
            ServerSocketChannel server = (ServerSocketChannel) key.channel();
            // 得到链接者的通道
            SocketChannel socketChannel = server.accept();
            System.out.println("有客户端链接了..");
            socketChannel.configureBlocking(false);
            // 设置这个key下次是可读的
            socketChannel.register(selector,SelectionKey.OP_READ);
        }
        // 可读
        if (key.isReadable()){

            ByteBuffer buffer = ByteBuffer.allocate(1024);
            SocketChannel channel = (SocketChannel) key.channel();

            int read = channel.read(buffer);
            if (read > 0){
                buffer.flip();
                String s = new String(buffer.array(), 0, read);
                System.out.println(s);
            }
            channel.register(selector,SelectionKey.OP_WRITE);
            buffer.clear();
        }
        // 可写
        if (key.isWritable()){

            ByteBuffer buffer = ByteBuffer.allocate(1024);
            SocketChannel channel = (SocketChannel) key.channel();

            buffer.put("我是内容".getBytes());

            channel.write(buffer);

        }

    }

    public static void main(String[] args) {
        try {
            new NIOServer().listen();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }



}
